using System;
using Moq;
using NUnit.Framework;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace Fines.Powershell.PowershellMSBuildTask.Tests
{
    [TestFixture]
    public class PowershellTest
    {
        Mock<ITaskItem> taskItemMock;
        private Powershell powershell;

        [SetUp]
        public void SetUp()
        {
            this.taskItemMock = new Mock<ITaskItem>();
            this.powershell = new Powershell();

        }

        [TearDown]
        public void TearDown()
        {
        }

        [Test]
        public void Script()
        {

            this.powershell.Script = taskItemMock.Object;
            Assert.AreSame( taskItemMock.Object, this.powershell.Script );
        }

        [Test]
        [ExpectedException(typeof(InvalidOperationException))]
        public void ScriptOrScriptFileRequired()
        {
            this.powershell.Execute();
        }

        [Test]
        public void Output()
        {
            Assert.IsNotNull( Attribute.GetCustomAttribute( typeof( Powershell ).GetProperty( "Output" ), typeof( OutputAttribute ) ) );
        }

        [Test]
        public void RunSimpleScript()
        {
            RunScript( "40 + 2");

            Assert.AreEqual( 1, this.powershell.Output.Length );
            Assert.AreEqual( "42", this.powershell.Output[ 0 ].ItemSpec );
        }

        [Test]
        public void MultilineScript()
        {
            this.RunScript( @"
$a = 4
$b = 38
$c = $a + $b
$c" 
                );

            Assert.AreEqual( "42", this.powershell.Output[ 0 ].ItemSpec );

        }

        [Test]
        public void TaskItems()
        {
            ITaskItem[] items = new ITaskItem[] { };

            this.powershell.TaskItems = items;
            Assert.AreSame( this.powershell.TaskItems, items );
        }

        [Test]
        public void TaskItemsInputToScript()
        {
            ITaskItem[] input = new ITaskItem[] { new TaskItem( "20" ), new TaskItem( "22" ) };
            this.powershell.TaskItems = input;

            this.RunScript( "[int]$taskitems[0].ItemSpec + [int]$taskitems[1].ItemSpec" );

            Assert.AreEqual( "42", this.powershell.Output[ 0 ].ItemSpec );
        }

        [Test]
        public void NoOutputForNullReturningScript()
        {
            this.RunScript( "$a = 42" );
            Assert.AreEqual( 0, this.powershell.Output.Length );
        }

        [Test]
        public void EmptyReturned()
        {
            this.RunScript( "$null" );
            Assert.AreEqual( String.Empty, this.powershell.Output[ 0 ].ItemSpec );
        }

        [Test]
        public void ShouldExit()
        {
            ((IPowershellTask)this.powershell).ShouldExit = true;
            Assert.IsTrue( ((IPowershellTask)this.powershell).ShouldExit );

            ((IPowershellTask)this.powershell).ShouldExit = false;
            Assert.IsFalse( ((IPowershellTask)this.powershell).ShouldExit );
        }

        [Test]
        public void ExitCode()
        {
            ((IPowershellTask)this.powershell).ExitCode = 42;
            Assert.AreEqual( 42, ((IPowershellTask)this.powershell).ExitCode );
        }

        [Test]
        public void VerbosePreference()
        {
            this.TestPreference( "VerbosePreference", "Continue" );
        }

        [Test]
        public void DebugPreference()
        {
            this.TestPreference( "DebugPreference", "Stop" );
        }

        [Test]
        public void ErrorActionPreference()
        {
            this.TestPreference( "ErrorActionPreference", "Continue" );
        }

        [Test]
        public void ShouldProcessPreference()
        {
            TestPreference("ShouldProcessPreference", "Stop" );
        }

        [Test]
        public void ProcessReturnPreference()
        {
            this.powershell.ProcessReturnPreference = true;
            Assert.IsTrue( this.powershell.ProcessReturnPreference );

            this.RunScript( "$ProcessReturnPreference" );
            Assert.AreEqual( true.ToString(), this.powershell.Output[ 0 ].ItemSpec );
        }

        [Test]
        public void Arguments()
        {
            this.powershell.Arguments = new[] { "Foo=Bar", "Baz=Bat" };
            this.RunScript( "$Foo; $Baz" );

            Assert.AreEqual( "Bar", this.powershell.Output[ 0 ].ItemSpec );
            Assert.AreEqual( "Bat", this.powershell.Output[ 1 ].ItemSpec );
        }


        private void TestPreference(string preference, object value)
        {
            this.powershell.GetType().GetProperty( preference ).SetValue( this.powershell, value, null );
            Assert.AreEqual( value, this.powershell.GetType().GetProperty( preference ).GetValue( this.powershell, null ) );

            this.RunScript( "$" + preference );
            Assert.AreEqual( value, this.powershell.Output[ 0 ].ItemSpec );
        }

        private void RunScript(string script)
        {
            this.taskItemMock.SetupGet( ti => ti.ItemSpec ).Returns( script );
            this.powershell.Script = this.taskItemMock.Object;

            Assert.IsTrue(this.powershell.Execute());
        }

        

        
    }
}
